package deadlock

import "fmt"
import "dumpwave"

func alu(
		decodeAlu	chan DEAL,
		dmuxAlu		chan DMAL,
		aluMux		chan ALMU,
		exception	chan int32,
		ls_addr 	chan uint32,
		ls_rw 		chan bool, 
		ls_data_in 	chan int32,
		ls_data_out 	chan int32,
		aluPc		chan uint32){
	
	var addr_offset uint32
	
	for{
		select{
			case deal :=<- decodeAlu://cmd_alu == deal.cmd
				fmt.Println("[ALU] Received instruction", deal.CMD)
				switch deal.CMD{
					case ADD:
						dmal:=<-dmuxAlu
						if (dmal.BUS1 >>31) + (dmal.BUS2 >>31) != ((dmal.BUS1+dmal.BUS2)>>31) {
							exception<-EX_ADES
						} else{
							exception<-EX_NO
						}
						fmt.Printf("[ALU] ADD: %d + %d = %d\n",dmal.BUS1,dmal.BUS2,dmal.BUS1+dmal.BUS2)
						aluMux<-ALMU{EXEC_TO_REG: dmal.BUS1+dmal.BUS2, CANCELLED:false}

					case SUB:
						dmal:=<-dmuxAlu
						if (dmal.BUS1 >>31) - (dmal.BUS2 >>31) != ((dmal.BUS1+dmal.BUS2)>>31) {
							exception<-EX_ADES
						} else{
							exception<-EX_NO
						}
						fmt.Printf("[ALU] SUB: %d - %d = %d\n",dmal.BUS1,dmal.BUS2,dmal.BUS1-dmal.BUS2)
						aluMux<-ALMU{EXEC_TO_REG: dmal.BUS1-dmal.BUS2, CANCELLED:false}
						
					case AND:
						dmal:=<-dmuxAlu
						exception<-EX_NO
						fmt.Printf("[ALU] AND: %d & %d = %d\n",dmal.BUS1,dmal.BUS2,dmal.BUS1 & dmal.BUS2)
						aluMux<-ALMU{EXEC_TO_REG: dmal.BUS1 & dmal.BUS2, CANCELLED:false}
						
					case LW:
						dmal:=<-dmuxAlu
						exception<-EX_NO
						if  uint32(deal.IMMEDIATE & 0x8000) == uint32(0) { //dmal.RD == OFFSET
								addr_offset = 0x00000000
						}else {
								addr_offset = 0xFFFF0000
						}
						addr_offset = addr_offset | uint32(deal.IMMEDIATE & 0xFFFF)
						fmt.Printf("[ALU] ALMU --> MUX\n")// (rs: 0x%x addr_offset: 0x%x)\n",deex.rs,addr_offset)
						
						//vAddr := dmal.BUS1+int32(addr_offset)
						ls_addr <- uint32(dmal.BUS1)+addr_offset
						ls_rw <- false
						data_out := <-ls_data_out
						
						//aluMux <- ALMU{EXEC_TO_REG:dmal.BUS1+int32(addr_offset), CANCELLED:false} //RS:base BUS1, RT:rt, RD:offset BUS2
						aluMux <- ALMU{EXEC_TO_REG: data_out , CANCELLED:false} //RS:base BUS1, RT:rt, RD:offset BUS2
						
					case SW:
						dmal:=<-dmuxAlu
						exception<-EX_NO
						if  uint32(deal.IMMEDIATE & 0x8000) == uint32(0) { //dmal.RD == OFFSET
								addr_offset = 0x00000000
						}else {
								addr_offset = 0xFFFF0000
						}
						addr_offset = addr_offset | uint32(deal.IMMEDIATE & 0xFFFF)
						fmt.Printf("[ALU] ALMU --> MUX\n")// (rs: 0x%x addr_offset: 0x%x)\n",deex.rs,addr_offset)

						ls_addr <- uint32(dmal.BUS1)+addr_offset
						ls_rw <- false
						ls_data_in <- dmal.BUS2
						fmt.Println("[ALU] Valor guardado",dmal.BUS2)
						
					case BEQ:
						dmal:=<-dmuxAlu
						exception<-EX_NO
						
						if dmal.BUS1 == dmal.BUS2 {
							if  uint32((deal.IMMEDIATE<<2) & 0x8000) == uint32(0) { //dmal.RD == OFFSET
								addr_offset = 0x00000000
							}else {
								addr_offset = 0xFFFF0000
							}
							addr_offset = addr_offset | uint32(deal.IMMEDIATE & 0xFFFF)
							aluPc <- addr_offset 
						}
				}
		}
	}
	
}